/**
 * Copyright (c) 2010-2011 julewa.com.  
 * All rights reserved. 
 * 
 * @author Huang Benhua
 * @date 2011-2-20
 * 
**/
package com.julewa.db.info;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.julewa.db.BeanInfo;
import com.julewa.db.DB;
import com.julewa.db.Entity;

public class EntityInfo implements BeanInfo{ 
	private String code = null;
	private String label = null;  
	private Class<?> typeClass = null;
	private boolean isEnt = false;
	private boolean autowire = false;
	private DB.DYNAMIC dynamic = null;
	private List<ColumnInfo> columns = null;
	private List<ColumnInfo> keys = null;
	private Map<String, ColumnInfo> allcolumns = null;
	
	public EntityInfo(String code, Class<?> clazz){
		_init_(code, clazz);
	}
	
	public EntityInfo(String code, String clazz){
		try {
			_init_(code, Class.forName(clazz));
		} catch (ClassNotFoundException e) {
			//
			e.printStackTrace();
		}
	}
	
	private void _init_(String code, Class<?> clazz){
		if(clazz == null)return;
		this.typeClass = clazz;
		this.code = code;
		this.label = code;
		//autowire
		if(typeClass.getAnnotation(Component.class) != null){
			Scope s =  typeClass.getAnnotation(Scope.class);
			autowire = (s != null && Entity.SCOPE.equals(s.value()));
		}
		//
		this.allcolumns = new HashMap<String, ColumnInfo>();
		
		//
		if(null != typeClass.getAnnotation(DB.USECACHE.class)){
			this.isEnt = Entity.class.isAssignableFrom(typeClass);
		}
		//
		 dynamic = typeClass.getAnnotation(DB.DYNAMIC.class);
		
		//
		Method[] ms = typeClass.getMethods();
		for(Method m:ms){
			PropertyInfo col = new PropertyInfo(m, this.typeClass);
			if(!col.isValid())continue;
			this.allcolumns.put(col.getCode(), col);
		}
		//
		List<Field> dependonFields = new ArrayList<Field>();
		Field fs[] = typeClass.getDeclaredFields();
		for(Field f:fs){
			if(f.getAnnotation(DB.DEPENDON.class) != null){
				dependonFields.add(f);
			}
			PropertyInfo col = new PropertyInfo(f);
			if(!col.isValid())continue;
			this.allcolumns.put(col.getCode(), col);
		}
		//
		for(Field f:dependonFields){
			DB.DEPENDON dp = f.getAnnotation(DB.DEPENDON.class);
			f.setAccessible(true);
			for(String v:dp.value()){
				if(v == null)continue;
				PropertyInfo c = (PropertyInfo)this.allcolumns.get(v.trim());
				if(c == null)continue;
				c.relativeFields.add(f);
			}
		}
		//
		this.columns = new ArrayList<ColumnInfo>();
		for(ColumnInfo c:this.allcolumns.values()){
			if(((PropertyInfo)c).isKey()){
				if(keys == null)keys = new ArrayList<ColumnInfo>();
				keys.add(c);
			}else{
				columns.add(c);
			}
		}
	}
	
	public boolean isAutowire(){
		return this.autowire;
	}
	
	public String getLabel(){
		return label;
	}
	
	public void setLabel(String label){
		this.label = label;
	}
	
	public String getCode() {
		return code;
	}
	
	public Class<?> getTypeClass() {
		return typeClass;
	}

	public Collection<ColumnInfo> getColumns() {
		return this.columns;
	}
 
	public Collection<ColumnInfo> getKeys() {
		return keys;
	}
	
	public boolean isDynamic() {
		return this.dynamic != null;
	}
	
	public DB.DYNAMIC getDynamicDef(){
		return this.dynamic;
	}

	public boolean isValid(){
		return keys != null;
	}
	
	public boolean isEntity(){
		return isEnt;
	}
	
	public ColumnInfo getColumn(String column){ 
		return allcolumns.get(column);
	};
	 
	public Collection<ColumnInfo> getAllColumns(){ 
		return allcolumns.values();
	};
	
	public <T> void copy(T from, T to) throws Exception{
		if(from == null || to == null || from == to)return;
		Collection<ColumnInfo> cols = getColumns();
		for(ColumnInfo col:cols){
			col.clone(from, to);
		}
	};
	
	public <T> void clone(T from, T to) throws Exception{
		if(from == null || to == null || from == to)return;
		Collection<ColumnInfo> cols = getAllColumns();
		for(ColumnInfo col:cols){
			col.clone(from, to);
		}
	};
	
}